import os
import cv2
import numpy as np
import math
from operator import itemgetter
from itertools import groupby

from flask import Blueprint, request, redirect, render_template, jsonify, url_for, send_from_directory, session
from flask_login import login_required

from application.models.database.base import db
# from application.models.tesseract import tesseract
from application.models.tesseract_kamada import detect_table_nonAI_ver2

from application.define import Const, RequestType, StateType, ALL_ID, INVALID_ID, Order, CUT_OUT_SIZE_DEFAULT, \
    DivideType, UpdateType, Shape
from application.models.database.projects import Projects
from application.models.database.areas import Areas, AreaTable
from application.models.database.context import Contexts, ContextsAddress, ContextAddressTable
from application.models.database.legends import Legends, Sizes
from application.models.database.parent_classes import ParentClasses
from application.models.database.categories import Categories
from application.models.database.symbols import Symbols
from application.models.database.option_columns import OptionColumns
from application.models.database.products import Products
from application.models.database.remarks import Remarks
from application.models.database.pages import Pages, Sections
from application.models.database.inspections import Inspections
from application.models.print.cut_out import CutOut


from config import LEGEND_DIRECTORY_NAME
from config import CLASSIFICATION_DIRECTORY_NAME
from config import get_app_config
from util.area_util import AreaUtil
from matplotlib.path import Path
from shapely.geometry import Polygon

editor = Blueprint(__name__, __name__)

"""
 WebPage
"""


@editor.route(Const.ROOT_URL + '/classification', methods=['GET'])
@login_required
def classification():
    return render_template('content/classification.html')


"""
 API
"""


@editor.route(Const.ROOT_URL + '/uploads/page_file/<filename>')
@login_required
def page_file(filename):
    from application import app
    projects = Projects()

    project_id = session['project_id']
    directory = projects.get_directory(project_id)
    if directory:
        return send_from_directory(directory, filename)
    app.logger.error("page_file == false")
    return redirect(__name__ + url_for('project'))


@editor.route(Const.ROOT_URL + '/uploads/area/<filename>')
@login_required
def uploadArea(filename):
    from application import app
    projects = Projects()

    project_id = session['project_id']
    root = projects.get_directory(project_id)
    directory = os.path.join(root, CLASSIFICATION_DIRECTORY_NAME)
    if directory:
        return send_from_directory(directory, filename)
    app.logger.error("area == false")
    return redirect(__name__ + url_for('project'))


@editor.route(Const.ROOT_URL + '/uploads/legend/<filename>')
@login_required
def uploadLegend(filename):
    from application import app
    projects = Projects()

    project_id = session['project_id']
    root = projects.get_directory(project_id)
    directory = os.path.join(root, LEGEND_DIRECTORY_NAME)
    if directory:
        return send_from_directory(directory, filename)
    app.logger.error("legend == false")
    return redirect(__name__ + url_for('project'))


@editor.route(Const.ROOT_URL + '/uploads/symbol/<filename>')
@login_required
def uploadSymbol(filename):
    from application import app

    directory = get_app_config().SYMBOL_DIRECTORY
    if directory:
        return send_from_directory(directory, filename)
    app.logger.error("symbol == false")
    return redirect(__name__ + url_for('project'))


@editor.route(Const.ROOT_URL + '/uploads/class_area/<filename>')
@login_required
def uploardClassArea(filename):
    from application import app
    projects = Projects()

    project_id = session['project_id']
    root = projects.get_directory(project_id)
    directory = os.path.join(root, CLASSIFICATION_DIRECTORY_NAME)
    if directory:
        return send_from_directory(directory, filename)
    app.logger.error("classification == false")
    return redirect(__name__ + url_for('project'))


'''
 @brief
    2 つのポリゴンが交差するかどうかを判断する PSDCD tengyanbo 2023/03/14 バグ #163）
  @details
    2 つのポリゴンが交差している (交差している) かどうかを判断する
  @return
    関数・それらが交差するかどうか
'''
def is_cross(vertexs_source, vertexs_target):
    arr_source = []
    x = 0
    y = 0
    for i in range(len(vertexs_source)):
        for key in vertexs_source[i]:
            if key == 'x':
                x = vertexs_source[i][key]
            else:
                y = vertexs_source[i][key]
        arr_source.append((x, y))
    arr_target = []
    for i in range(len(vertexs_target)):
        for key in vertexs_target[i]:
            if key == 'x':
                x = vertexs_target[i][key]
            else:
                y = vertexs_target[i][key]
        arr_target.append((x, y))
    source_path = Polygon(arr_source)
    target_path = Polygon(arr_target)
    return target_path.intersects(source_path)


'''
 @brief
    2 つのポリゴンに PSDCD tengyanbo 2023/03/14 バグ #163）
  @details
    2 つのポリゴンに
  @return
    関数・含まれるかどうか
'''
def is_contain(vertexs_source, vertexs_target):
    arr_source = []
    x = 0
    y = 0
    for i in range(len(vertexs_source)):
        for key in vertexs_source[i]:
            if key == 'x':
                x = vertexs_source[i][key]
            else:
                y = vertexs_source[i][key]
        arr_source.append((x, y))
    arr_target = []
    for i in range(len(vertexs_target)):
        for key in vertexs_target[i]:
            if key == 'x':
                x = vertexs_target[i][key]
            else:
                y = vertexs_target[i][key]
        arr_target.append((x, y))
    source_path = Path(arr_source)
    target_path = Path(arr_target)
    return target_path.contains_path(source_path)


@editor.route(Const.ROOT_URL + '/area', methods=['POST'])
@login_required
def area():
    dict = request.json if ('application/json' in request.headers['Content-Type']) else {
        'req': int(request.form['req']),
    }

    req = dict['req']
    if 'project_id' in session:
        project_id = session['project_id']
    areas = Areas()
    contexts = Contexts()
    legends = Legends()
    projects = Projects()

    if 'project_id' in session:
        root = projects.get_directory(project_id)
        area_directory = os.path.join(root, CLASSIFICATION_DIRECTORY_NAME)

    if req == RequestType.info:
        if 'page_id' in dict:
            page_id = dict['page_id']
        else:
            page_id = ALL_ID
        state = dict['state']
        if state == StateType.normal_state:
            join_list = areas.get_join_list(project_id=project_id, page_id=page_id, is_dict=True)
            project_entry = projects.get_entry(id=project_id, is_dict=True)
            return jsonify(list=join_list, project=project_entry)
        elif state == StateType.single_state:
            area_id = dict['area_id']
            join_list = areas.get_join_area(area_id=area_id, project_id=project_id, page_id=page_id, is_dict=True)
            return jsonify(list=join_list)
        elif state == StateType.del_state:
            dict = request.json['data']
            id_list = [item['id'] for item in dict]
            join_list = areas.get_join_list(id_list=id_list, project_id=project_id, page_id=page_id, is_dict=True)
            return jsonify(list=join_list)
        elif state == StateType.area_order_list:
            order_list = request.json['orders']
            #print(order_list)
            join_list = areas.get_list_ByOrder(order_list=order_list, project_id=project_id, page_id=page_id, is_dict=True)
            return jsonify(list=join_list)
        # 凡例の動的表示のために追加 20221020 H.Uemura
        elif state == StateType.area_symbol_state:
            rect = dict['rect']

            x1 = rect['x1']
            y1 = rect['y1']
            x2 = rect['x2']
            y2 = rect['y2']

            #print('rect', x1, y1, x2, y2)

            #dt_now = datetime.datetime.now()
            #print("DB Search start", dt_now)

            join_list = areas.get_join_list_in_area(project_id=project_id, page_id=page_id, is_dict=True, rect= rect)

            #dt_now = datetime.datetime.now()
            #print("DB Search end", dt_now, len(join_list))

            use_area_list = []
            for item in join_list:
                #print(str(item['vertexs'][0]['x']),str(item['vertexs'][0]['y']))
                if 'legend_id' in item:
                    #print(item['legend_id'])
                    use_area_list.append(item)

            #dt_now = datetime.datetime.now()
            #print("legend list end", dt_now, len(use_area_list))

            project_entry = projects.get_entry(id=project_id, is_dict=True)

            #dt_now = datetime.datetime.now()
            #print("get_entry end", dt_now)

            return jsonify(list=use_area_list, project=project_entry)

        #elif state == StateType.all_state:
        #    join_list = areas.get_join_list(order=Order.area_square, is_dict=True)
        #    return jsonify(list=join_list)
        else:
            return jsonify(judge=False, id=INVALID_ID)
    #  @brief add start tengyanbo #19
    if req == RequestType.add_bulk:
        dict = request.json['data']
        for dict_item in dict:
            page_id = dict_item['page_id']
            dict_item['project_id'] = project_id
            order = dict_item['order']
            dict_item['is_manual'] = True             # 手動追加
            dict_item['z_index'] = areas.get_last_z_index(project_id=project_id, page_id=page_id, order=order) + 1
            #  @brief add start 領域判定の改善 PSDCD tengyanbo 2023/03/14 バグ#163
            filters = []
            #  @brief add start 建物領域と凡例設定領域などの別領域の重なりチェックと入れ子チェック PSDCD tengyanbo 2023/03/21 作業管理#265
            if dict_item['order'] == Order.area_rect or dict_item['order'] == Order.area_polygon:
                filters.append(db.or_(AreaTable.order == Order.area_rect, AreaTable.order == Order.area_polygon))
            elif dict_item['order'] == Order.area_legend:
                filters.append(db.or_(AreaTable.order == Order.area_legend))
            elif dict_item['order'] == Order.building:
                filters.append(db.or_(AreaTable.order == Order.building))
            if len(filters) == 0:
                pass
            else:
                #  @brief add end 建物領域と凡例設定領域などの別領域の重なりチェックと入れ子チェック PSDCD tengyanbo 2023/03/21 作業管理#265
                area_list = areas.get_list(project_id=project_id, filters=filters, page_id=page_id)
                dict_item['out_area'] = ''
                for i in range(len(area_list)):
                    #  @brief add  既存のものには新しいものが含まれます PSDCD tengyanbo 2023/03/14 バグ#163
                    if is_contain(dict_item['vertexs'], area_list[i].vertexs):
                        # 已经有得包含新增的  新增的外部是已经有的
                        dict_item['have_out'] = True
                        dict_item['out_area'] += (str(area_list[i].id) + '@')
                    #  @brief add  新しいものには既存のものが含まれます PSDCD tengyanbo 2023/03/14 バグ#163
                    elif is_contain(area_list[i].vertexs, dict_item['vertexs']):
                        #  brief add  外観の有無 PSDCD tengyanbo 2023/03/14 バグ#163
                        area_list[i].have_out = True
                        #  brief add  文字列の連結 PSDCD tengyanbo 2023/03/14 バグ#163
                        out_area = '' if area_list[i].out_area == None else area_list[i].out_area
                        out_area += (str(area_list[0].id + 1) + '@')
                        area_list[i].out_area = out_area
                        areas.update(areas.to_dict(area_list[i]))
                    elif is_cross(dict_item['vertexs'], area_list[i].vertexs):
                        dict_item['is_cross'] = True
                        #  brief add  既存のエリアのステータスを更新する PSDCD tengyanbo 2023/03/14 バグ#163
                        area_list[i].is_cross = True
                        areas.update(areas.to_dict(area_list[i]))
            # @brief add end 領域判定の改善 PSDCD tengyanbo 2023/03/14 バグ#163
        id_list = areas.insert(dict)
        if not id_list:
            return jsonify(judge=False, id=INVALID_ID)
        if order == Order.area_legend:
            return jsonify(judge=True, id=id_list[0])
        if order == Order.area_square:
            legend_id = request.json['legend_id']
            if legend_id != INVALID_ID:
                entry = {
                    'id': INVALID_ID,
                    'symbol_area_id': id_list[0],
                    'area_id': None,
                    'legend_id': legend_id,
                }
                legends.insert_map([entry])

            return jsonify(judge=True, id=id_list[0], area=dict)
        for dict_item in dict:
            context_dict = {
                'id': INVALID_ID,
                'area_id': id_list[0],
                'multiplier': dict_item['multiplier'],
                'name_type': dict_item['name_type'],
                'name': dict_item['name'],
            }
            context_id_list = contexts.insert([context_dict])
            if not context_id_list:
                return jsonify(judge=False, id=INVALID_ID)
        return jsonify(judge=True, id=id_list[0], area=dict)
    #  @brief add start tengyanbo #19
    if req == RequestType.add:
        dict = request.json['data']
        dict['project_id'] = project_id
        page_id = dict['page_id']
        order = dict['order']
        dict['is_manual'] = True             # 手動追加
        dict['z_index'] = areas.get_last_z_index(project_id=project_id, page_id=page_id, order=order) + 1
        #  @brief add start 領域判定の改善 PSDCD tengyanbo 2023/03/14 バグ#163
        filters = []
        #  @brief add start 建物領域と凡例設定領域などの別領域の重なりチェックと入れ子チェック PSDCD tengyanbo 2023/03/21 作業管理#265
        if dict['order'] == Order.area_rect or dict['order'] == Order.area_polygon:
            filters.append(db.or_(AreaTable.order == Order.area_rect, AreaTable.order == Order.area_polygon))
        elif dict['order'] == Order.area_legend:
            filters.append(db.or_(AreaTable.order == Order.area_legend))
        elif dict['order'] == Order.building:
            filters.append(db.or_(AreaTable.order == Order.building))
        if len(filters) == 0:
            pass
        else:
            #  @brief add end 建物領域と凡例設定領域などの別領域の重なりチェックと入れ子チェック PSDCD tengyanbo 2023/03/21 作業管理#265
            area_list = areas.get_list(project_id=project_id, filters=filters, page_id=page_id)
            dict['out_area'] = ''
            for i in range(len(area_list)):
                #  @brief add  既存のものには新しいものが含まれます PSDCD tengyanbo 2023/03/14 バグ#163
                if is_contain(dict['vertexs'], area_list[i].vertexs):
                    # 已经有得包含新增的  新增的外部是已经有的
                    dict['have_out'] = True
                    dict['out_area'] += (str(area_list[i].id) + '@')
                #  @brief add  新しいものには既存のものが含まれます PSDCD tengyanbo 2023/03/14 バグ#163
                elif is_contain(area_list[i].vertexs, dict['vertexs']):
                    #  brief add  外観の有無 PSDCD tengyanbo 2023/03/14 バグ#163
                    area_list[i].have_out = True
                    #  brief add  文字列の連結 PSDCD tengyanbo 2023/03/14 バグ#163
                    out_area = '' if area_list[i].out_area == None else area_list[i].out_area
                    out_area += (str(area_list[0].id + 1) + '@')
                    area_list[i].out_area = out_area
                    areas.update(areas.to_dict(area_list[i]))
                elif is_cross(dict['vertexs'], area_list[i].vertexs):
                    dict['is_cross'] = True
                    #  brief add  既存のエリアのステータスを更新する PSDCD tengyanbo 2023/03/14 バグ#163
                    area_list[i].is_cross = True
                    areas.update(areas.to_dict(area_list[i]))
        # @brief add end 領域判定の改善 PSDCD tengyanbo 2023/03/14 バグ#163
        id_list = areas.insert([dict])
        if not id_list:
            return jsonify(judge=False, id=INVALID_ID)
        if order == Order.area_legend:
            return jsonify(judge=True, id=id_list[0])
        if order == Order.area_square:
            legend_id = request.json['legend_id']
            if legend_id != INVALID_ID:
                entry = {
                    'id': INVALID_ID,
                    'symbol_area_id': id_list[0],
                    'area_id': None,
                    'legend_id': legend_id,
                }
                legends.insert_map([entry])

            return jsonify(judge=True, id=id_list[0], area=dict)

        context_dict = {
            'id': INVALID_ID,
            'area_id': id_list[0],
            'multiplier': dict['multiplier'],
            'name_type': dict['name_type'],
            'name': dict['name'],
        }
        context_id_list = contexts.insert([context_dict])
        if not context_id_list:
            return jsonify(judge=False, id=INVALID_ID)
        return jsonify(judge=True, id=id_list[0])

    if req == RequestType.update:
        dict = request.json['data']
        dict['project_id'] = project_id

        # Check済の更新
        if 'check_status' in dict:
            #print(dict)
            if 'shape' in dict:
                areas.updateChecked(dict['project_id'], dict['shape'], dict['check_status'])
                return jsonify(judge=False, id=INVALID_ID)
            if 'ids' in dict:
                areas.updateCheckedByID(dict['ids'], dict['check_status'])
                return jsonify(judge=False, id=INVALID_ID)

        dict['is_manual'] = True             # 手動修正
        # @brief add start 領域判定の改善 PSDCD tengyanbo 2023/03/14 バグ#163
        filters = []
        filters.append(db.or_(AreaTable.order == Order.area_rect, AreaTable.order == Order.area_polygon))
        area_list = areas.get_list(project_id=project_id, filters=filters)
        filters_id = []
        filters_id.append(AreaTable.id == dict['id'])
        update_area = areas.get_list(project_id=project_id, filters=filters_id)[0]
        page_id = update_area.page_id
        filter_area_list = []
        for area_list in area_list:
            if area_list.id != dict['id'] and  area_list.page_id == page_id:
                filter_area_list.append(area_list)
        #  @brief add 最初にリセット PSDCD tengyanbo 2023/03/14 バグ#163
        dict['out_area'] = ''
        dict['is_cross'] = False
        dict['have_out'] = False
        #  @brief add 矩形と多角形以外のタイプは処理されません PSDCD tengyanbo 2023/03/16 作業管理#264
        if dict['order'] == Order.area_rect or dict['order'] == Order.area_polygon:
            for filter_area in filter_area_list:
                if is_contain(update_area.vertexs, filter_area.vertexs):
                    pass
                elif is_contain(filter_area.vertexs, update_area.vertexs):
                    out_area = '' if filter_area.out_area == None else filter_area.out_area
                    out_area = out_area.replace((str(update_area.id) + '@'), "")
                    filter_area.out_area = out_area
                    #  @brief add 既知の包含領域がまだ外部にあるかどうか PSDCD tengyanbo 2023/03/14 バグ#163
                    if filter_area.out_area == "" or filter_area.out_area is None:
                        filter_area.have_out = False
                    areas.update(areas.to_dict(filter_area))
                elif is_cross(update_area.vertexs, filter_area.vertexs):
                    filter_area_list_no_cross = filter(lambda area: area.id != filter_area.id, filter_area_list)
                    cross_flag = False
                    # @brief add 真を返す十字架があります PSDCD tengyanbo 2023/03/14 バグ#163
                    for area_no_cross in filter_area_list_no_cross:
                        if is_contain(area_no_cross.vertexs, filter_area.vertexs):
                            pass
                        elif is_contain(filter_area.vertexs, area_no_cross.vertexs):
                            pass
                        elif is_cross(area_no_cross.vertexs, filter_area.vertexs):
                            filter_area.is_cross = True
                            cross_flag = True
                    if cross_flag is False:
                        filter_area.is_cross = False
                    areas.update(areas.to_dict(filter_area))
            #  @brief add 更新ステータス PSDCD tengyanbo 2023/03/14 バグ#163
            for i in range(len(filter_area_list)):
                if is_contain(dict['vertexs'], filter_area_list[i].vertexs):
                    dict['have_out'] = True
                    dict['out_area'] += (str(update_area.id) + '@')
                #  @brief add 更新されるインクルージョンはすでに利用可能です PSDCD tengyanbo 2023/03/14 バグ#163
                elif is_contain(filter_area_list[i].vertexs, dict['vertexs']):
                    filter_area_list[i].have_out = True
                    out_area = '' if filter_area_list[i].out_area == None else filter_area_list[i].out_area
                    out_area += (str(update_area.id) + '@')
                    filter_area_list[i].out_area = out_area
                    areas.update(areas.to_dict(filter_area_list[i]))
                elif is_cross(dict['vertexs'], filter_area_list[i].vertexs):
                    dict['is_cross'] = True
                    filter_area_list[i].is_cross = True
                    areas.update(areas.to_dict(filter_area_list[i]))
        #  @brief add end 領域判定の改善 PSDCD tengyanbo 2023/03/14 バグ#163
        if not areas.update(dict):
            return jsonify(judge=False, id=INVALID_ID)

        # 拾い出し画像更新
        if not get_app_config().AWS_USED:
            file_name = str(dict['id']) + ".png"
            file_path = os.path.join(area_directory, file_name)
            if os.path.exists(file_path):
                pages = Pages()
                remarks = Remarks()
                remark_list = remarks.get_list(project_id=project_id, is_dict=True)
                symbol_scale = remark_list[0]['symbol_scale']
                space = math.floor(CUT_OUT_SIZE_DEFAULT * float(symbol_scale))

                rect = {
                    'x': dict['vertexs'][0]['x'] - space,
                    'y': dict['vertexs'][0]['y'] - space,
                    'w': space * 2,
                    'h': space * 2,
                }
                top = rect['y']
                bottom = rect['y'] + rect['h']
                left = rect['x']
                right = rect['x'] + rect['w']
                page = pages.get_entry(dict['page_id'], is_dict=True)
                page_image = _imread(page['path'])
                trim_image = page_image[top:bottom, left:right]
                cv2.imwrite(file_path, trim_image)

        return jsonify(judge=True, dict=dict)

    if req == RequestType.target:
        area = request.json['data']
        legend_id = request.json['legend_id']

        # 自動拾い出し判定falseへの更新
        if area['legend_id'] != legend_id:
            dict = request.json['data']
            dict['project_id'] = project_id
            dict['is_manual'] = True             # 手動修正
            areas.update(dict)

        map_entry = legends.get_map_entry(symbol_area_id=area['id'], is_dict=True)
        if map_entry:
            area['legend_id'] = legend_id
            map_entry['legend_id'] = legend_id
            legends.update_map(map_entry)

        sizes = Sizes()
        size_entry = sizes.get_entry(legend_id, is_dict=True)
        area['size'] = size_entry

        return jsonify(judge=True, area=area)

    if req == RequestType.delete:
        dict = request.json['data']

        id_list = [item['id'] for item in dict]
        #  @brief add start 領域判定の改善 PSDCD tengyanbo 2023/03/14 バグ#163
        filters = []
        #  @brief add start 建物領域と凡例設定領域などの別領域の重なりチェックと入れ子チェック PSDCD tengyanbo 2023/03/21 作業管理#265
        for item_dict in dict:
            if item_dict['order'] == Order.area_rect or item_dict['order'] == Order.area_polygon:
                filters.append(db.or_(AreaTable.order == Order.area_rect, AreaTable.order == Order.area_polygon))
            elif item_dict['order'] == Order.area_legend:
                filters.append(db.or_(AreaTable.order == Order.area_legend))
            elif item_dict['order'] == Order.building:
                filters.append(db.or_(AreaTable.order == Order.building))
            if len(filters) != 0:
                area_list = areas.get_list(project_id=project_id, filters=filters)
                #  @brief add end 建物領域と凡例設定領域などの別領域の重なりチェックと入れ子チェック PSDCD tengyanbo 2023/03/21 作業管理#265
                for i in range(len(id_list)):
                    filters_id = []
                    filters_id.append(AreaTable.id == id_list[i])
                    page_id = areas.get_list(project_id=project_id, filters=filters_id)[0].page_id
                    filter_area_list = []
                    for area_filter in area_list:
                        if area_filter.page_id == page_id and area_filter.id != id_list[i]:
                            filter_area_list.append(area_filter)
                    for filter_area in filter_area_list:
                        #  @brief add 既知には新しく削除されたものが含まれています PSDCD tengyanbo 2023/03/14 バグ#163
                        if is_contain(dict[i]['vertexs'], filter_area.vertexs):
                            pass
                        #  @brief add 除去される介在物は既知です PSDCD tengyanbo 2023/03/16 バグ#163
                        elif is_contain(filter_area.vertexs, dict[i]['vertexs']):
                            out_area = '' if filter_area.out_area == None else filter_area.out_area
                            out_area = out_area.replace((str(id_list[i]) + '@'), "")
                            #  @brief add 自己封じ込めを処理する PSDCD tengyanbo 2023/03/16 作業管理 #264
                            while out_area.find(str(filter_area.id) + '@') != -1:
                                out_area = out_area.replace((str(filter_area.id) + '@'), "")
                            filter_area.out_area = out_area
                            #  @brief add 既知の包含領域がまだ外部にあるかどうか PSDCD tengyanbo 2023/03/14 バグ#163
                            if filter_area.out_area == "" or filter_area.out_area is None:
                                filter_area.have_out = False
                            areas.update(areas.to_dict(filter_area))
                        elif is_cross(dict[i]['vertexs'], filter_area.vertexs):
                            filter_area_list_no_cross = filter(lambda area: area.id != filter_area.id, filter_area_list)
                            cross_flag = False
                            #  @brief add 真を返す十字架があります PSDCD tengyanbo 2023/03/14
                            for area_no_cross in filter_area_list_no_cross:
                                if is_contain(area_no_cross.vertexs, filter_area.vertexs):
                                    pass
                                elif is_contain(filter_area.vertexs, area_no_cross.vertexs):
                                    pass
                                elif is_cross(area_no_cross.vertexs, filter_area.vertexs):
                                    filter_area.is_cross = True
                                    cross_flag = True
                            if cross_flag is False:
                                filter_area.is_cross = False
                            areas.update(areas.to_dict(filter_area))
        #  @brief add end 領域判定の改善 PSDCD tengyanbo 2023/03/14 バグ#163
        areas.delete(id_list)

        # 拾い出し画像削除
        if not get_app_config().AWS_USED:
            for i in range(len(id_list)):
                order = dict[i]['order']
                if order == Order.area_square:
                    file_name = str(id_list[i]) + ".png"
                    file_path = os.path.join(area_directory, file_name)
                    if os.path.exists(file_path):
                        os.remove(file_path)

        return jsonify(judge=True)

    if req == RequestType.info_all:
        area_list = areas.get_list(filters=[], project_id=project_id, is_dict=True)
        return jsonify(area_list=area_list)


@editor.route(Const.ROOT_URL + '/class-area', methods=['POST'])
@login_required
def classArea():
    dict = request.json if ('application/json' in request.headers['Content-Type']) else {
        'req': int(request.form['req']),
    }

    req = dict['req']
    project_id = session['project_id']
    projects = Projects()
    areas = Areas()
    legends = Legends()

    if req == RequestType.info:
        root = projects.get_directory(project_id)
        area_directory = os.path.join(root, CLASSIFICATION_DIRECTORY_NAME)
        order_areas_list = areas.get_order_list(project_id=project_id, order=Order.area_square, is_dict=True)
        for area in order_areas_list:
            map_entry = legends.get_map_entry(symbol_area_id=area['id'], is_dict=True)
            if map_entry:
                area['lg_type'] = map_entry['legend_id']
            else:
                area['lg_type'] = INVALID_ID

            file_name = str(area['id']) + ".png"
            file_path = os.path.join(area_directory, file_name)
            area['path'] = areas.to_upload_path(file_path)

        return jsonify(judge=True, list=order_areas_list)

    if req == RequestType.add:
        pass

    if req == RequestType.update:
        dict = request.json['data']
        for area in dict:
            map_entry = legends.get_map_entry(symbol_area_id=area['id'], is_dict=True)
            if map_entry:
                map_entry['legend_id'] = area['lg_type']
                legends.update_map(map_entry)
            else:
                entry = {
                    'id': INVALID_ID,
                    'symbol_area_id': area['id'],
                    'area_id': None,
                    'legend_id': area['lg_type'],
                }
                legends.insert_map([entry])
        return jsonify(judge=True)

    if req == RequestType.target:
        pass

    if req == RequestType.delete:
        pass


@editor.route(Const.ROOT_URL + '/context', methods=['POST'])
@login_required
def context():
    dict = request.json if ('application/json' in request.headers['Content-Type']) else {
        'req': int(request.form['req']),
    }

    req = dict['req']
    contexts = Contexts()

    if req == RequestType.info:
        pass

    if req == RequestType.add:
        pass

    if req == RequestType.update:
        dict = request.json['data']
        if not contexts.update(dict):
            return jsonify(judge=False, id=INVALID_ID)
        return jsonify(judge=True)

    if req == RequestType.target:
        pass

    if req == RequestType.delete:
        pass


@editor.route(Const.ROOT_URL + '/legendtable', methods=['POST'])
@login_required
def legendtable():
    dict = request.json if ('application/json' in request.headers['Content-Type']) else {
        'req': int(request.form['req']),
    }

    req = dict['req']
    project_id = session['project_id']
    legends = Legends()

    if req == RequestType.info:
        list = legends.get_list(project_id=project_id, is_dict=True)
        for item in list:
            if item['area_path']:
                item['area_path'] = legends.to_upload_path(item['area_path'])
            if item['path']:
                item['path'] = legends.to_upload_path(item['path'])
        return jsonify(judge=True, list=list)

    if req == RequestType.add:
        legend_list = legends.get_list(project_id=project_id, is_dict=True)
        if legend_list:
            return jsonify(judge=True)

        areas = Areas()
        order_areas_list = areas.get_order_list(project_id=project_id, order=Order.area_legend, is_dict=True)
        if len(order_areas_list) == 0:
            return jsonify(judge=False, isArea=False)

        res = recognize_legend(project_id)
        if not res:
            return jsonify(judge=False, id=INVALID_ID, isArea=True)
        return jsonify(judge=True)

    if req == RequestType.update:
        legend_list = legends.get_list(project_id=project_id, is_dict=True)
        id_list = [item['id'] for item in legend_list]
        areas = Areas()
        for id in id_list:
            map_list = legends.get_map_list(legend_id=id, is_dict=True)
            symbol_area_ids = [e['symbol_area_id'] for e in map_list]
            areas.delete(symbol_area_ids)

            legends.delete(id)

        res = recognize_legend(project_id)
        if not res:
            return jsonify(judge=False, id=INVALID_ID)
        return jsonify(judge=True)

    if req == RequestType.target:
        pass

    if req == RequestType.delete:
        pass


@editor.route(Const.ROOT_URL + '/legend', methods=['POST'])
@login_required
def legend():
    dict = request.json if ('application/json' in request.headers['Content-Type']) else {
        'req': int(request.form['req']),
    }

    req = dict['req']
    project_id = session['project_id']
    legends = Legends()

    if req == RequestType.info:
        list = legends.get_list(project_id=project_id, is_dict=True)
        for item in list:
            if item['area_path']:
                item['area_path'] = legends.to_upload_path(item['area_path'])
            if item['path']:
                item['path'] = legends.to_upload_path(item['path'])
        return jsonify(judge=True, list=list)

    if req == RequestType.add:
        last_index = legends.get_last_index(project_id=project_id)
        dict = {
            'project_id': project_id,
            'symbol_id': -1,
            'area_path': "",
            'name': "凡例",
            'product_name': "",
            'path': "",
            'index': last_index + 1,
            'option': {},
        }
        id_list = legends.insert([dict])
        if not id_list:
            return jsonify(judge=False, id=INVALID_ID)
        return jsonify(judge=True)

    if req == RequestType.update:
        projects = Projects()
        root = projects.get_directory(project_id)
        legend_directory = os.path.join(root, LEGEND_DIRECTORY_NAME)
        if not os.path.exists(legend_directory):
            os.makedirs(legend_directory)
        symbol_directory = get_app_config().SYMBOL_DIRECTORY

        legend = request.json['legend']
        if legend['path']:
            legend_base_name = os.path.basename(legend['path']).split('?')[0]
            legend_path = os.path.join(legend_directory, legend_base_name)
            legend['path'] = legend_path

        if legend['area_path']:
            legend_area_base_name = os.path.basename(legend['area_path']).split('?')[0]
            legend_area_path = os.path.join(legend_directory, legend_area_base_name)
            legend['area_path'] = legend_area_path

        symbol = request.json['symbol']
        symbol_base_name = os.path.basename(symbol['path']).split('?')[0]
        symbol_path = os.path.join(symbol_directory, symbol_base_name)

        legendName = request.json['legendName']
        productName = request.json['productName']

        legend['symbol_id'] = symbol['id']
        if legendName or productName:
            legend['name'] = legendName
            legend['product_name'] = productName
        else:
            legend['name'] = symbol['name']
            legend['product_name'] = ""

        if not legend['area_path']:
            symbol_image = _imread(symbol_path)

            file_name = os.path.splitext(os.path.basename(symbol_path))[0]
            new_file_name = file_name + '.png'
            new_legend_path = os.path.join(legend_directory, new_file_name)
            if os.path.exists(new_legend_path):
                os.remove(new_legend_path)

            if legend['path']:
                if os.path.exists(legend_path):
                    os.remove(legend_path)

            temp_path = os.path.join(legend_directory, 'temp.png')
            cv2.imwrite(temp_path, symbol_image)
            os.rename(temp_path, new_legend_path)
            legend['path'] = new_legend_path

        res = legends.update(legend)
        if not res:
            return jsonify(judge=False, id=INVALID_ID)
        return jsonify(judge=True)

    if req == RequestType.target:
        list = request.json['data']
        for i, entity in enumerate(list):
            entity['index'] = i
        list = sorted(list, key=lambda x: x['id'], reverse=True)
        res = legends.bulk_update(list)
        if not res:
            return jsonify(judge=False, id=INVALID_ID)
        return jsonify(judge=True)

    if req == RequestType.delete:
        id = request.json['data']

        map_list = legends.get_map_list(legend_id=id, is_dict=True)
        symbol_area_ids = [e['symbol_area_id'] for e in map_list]
        areas = Areas()
        areas.delete(symbol_area_ids)

        legends.delete(id)
        return jsonify(judge=True)


@editor.route(Const.ROOT_URL + '/parent-class', methods=['POST'])
@login_required
def parent_class():
    dict = request.json if ('application/json' in request.headers['Content-Type']) else {
        'req': int(request.form['req']),
    }

    req = dict['req']
    parent_classes = ParentClasses()

    if req == RequestType.info:
        list = parent_classes.get_list(is_dict=True)
        if not list:
            return jsonify(judge=False, id=INVALID_ID)
        return jsonify(judge=True, list=list)

    if req == RequestType.add:
        pass

    if req == RequestType.update:
        pass

    if req == RequestType.target:
        pass

    if req == RequestType.delete:
        pass


@editor.route(Const.ROOT_URL + '/category', methods=['POST'])
@login_required
def category():
    dict = request.json if ('application/json' in request.headers['Content-Type']) else {
        'req': int(request.form['req']),
    }

    req = dict['req']
    categories = Categories()

    if req == RequestType.info:
        dict = request.json['data']
        list = categories.get_list(parent_class_id=dict, is_dict=True)
        if not list:
            return jsonify(judge=False, id=INVALID_ID)
        return jsonify(judge=True, list=list)

    if req == RequestType.add:
        pass

    if req == RequestType.update:
        pass

    if req == RequestType.target:
        pass

    if req == RequestType.delete:
        pass


@editor.route(Const.ROOT_URL + '/symbol', methods=['POST'])
@login_required
def symbol():
    dict = request.json if ('application/json' in request.headers['Content-Type']) else {
        'req': int(request.form['req']),
    }

    req = dict['req']
    symbols = Symbols()

    if req == RequestType.info:
        dict = request.json['data']
        list = symbols.get_list(category_id=dict, is_dict=True)
        if not list:
            return jsonify(judge=False, id=INVALID_ID)
        if list[0].get('index') is None:
            i = len(list) - 1
            for entity in list:
                entity['index'] = i
                i = i - 1
            symbols.bulk_update(list)
        for item in list:
            item['path'] = symbols.to_upload_path(item['path'])

        return jsonify(judge=True, list=list)

    if req == RequestType.add:
        category_id = request.json['data']
        last_index = symbols.get_last_index(category_id)
        dict = {
            'category_id': category_id,
            'name': "シンボル",
            'header': "",
            'line': "",
            'path': "",
            'option_item': {},
            'index': last_index + 1,
        }
        id_list = symbols.insert([dict])
        if not id_list:
            return jsonify(judge=False, id=INVALID_ID)
        return jsonify(judge=True)

    if req == RequestType.update:
        pass

    if req == RequestType.target:
        dict = request.json['data']
        list = symbols.get_list(is_dict=True)
        if not list:
            return jsonify(judge=False, id=INVALID_ID)
        if list[0].get('index') is None:
            i = len(list) - 1
            for entity in list:
                entity['index'] = i
                i = i - 1
            symbols.bulk_update(list)
        for item in list:
            item['path'] = symbols.to_upload_path(item['path'])

        import difflib
        import unicodedata
        target = unicodedata.normalize('NFKC', dict)
        name_list = [item['name'] for item in list]
        diff_list = difflib.get_close_matches(target, name_list, cutoff=0.3, n=10)
        res_list = [item for item in list if item['name'] in diff_list]

        return jsonify(judge=True, list=res_list)

    if req == RequestType.delete:
        id = request.json['data']
        symbols.delete(id)
        return jsonify(judge=True)


@editor.route(Const.ROOT_URL + '/option-column', methods=['POST'])
@login_required
def option_column():
    dict = request.json if ('application/json' in request.headers['Content-Type']) else {
        'req': int(request.form['req']),
    }

    req = dict['req']
    option_columns = OptionColumns()

    if req == RequestType.info:
        list = option_columns.get_list(is_dict=True)
        if not list:
            return jsonify(judge=False, id=INVALID_ID)
        return jsonify(judge=True, list=list)

    if req == RequestType.add:
        pass

    if req == RequestType.update:
        pass

    if req == RequestType.target:
        pass

    if req == RequestType.delete:
        pass


@editor.route(Const.ROOT_URL + '/product', methods=['POST'])
@login_required
def product():
    dict = request.json if ('application/json' in request.headers['Content-Type']) else {
        'req': int(request.form['req']),
    }

    req = dict['req']
    products = Products()

    if req == RequestType.info:
        symbol_id = request.json['symbol_id']
        product_list = products.get_list(symbol_id=symbol_id, is_dict=True)
        if not product_list:
            return jsonify(judge=False, id=INVALID_ID)
        if product_list[0].get('index') is None:
            i = len(product_list) - 1
            for entity in product_list:
                entity['index'] = i
                i = i - 1
            products.bulk_update(product_list)
        if product_list[0].get('headers') is None:
            header = list(sorted(product_list[0]['option'].keys()))
            for entity in product_list:
                entity['headers'] = {
                    'header': header,
                }
            products.bulk_update(product_list)
        return jsonify(judge=True, list=product_list)

    if req == RequestType.add:
        pass

    if req == RequestType.update:
        pass

    if req == RequestType.target:
        dict = request.json['data']
        symbol_id = request.json['symbol_id']
        product_list = products.get_list(symbol_id=symbol_id, is_dict=True)
        if not product_list:
            return jsonify(judge=False, id=INVALID_ID)

        entries = [item for item in product_list if item['option'] == dict]
        if not entries:
            return jsonify(judge=False, id=INVALID_ID)
        return jsonify(judge=True, entry=entries[0])

    if req == RequestType.delete:
        pass


@editor.route(Const.ROOT_URL + '/remark', methods=['POST'])
@login_required
def remark():
    dict = request.json if ('application/json' in request.headers['Content-Type']) else {
        'req': int(request.form['req']),
    }

    req = dict['req']
    remarks = Remarks()

    if req == RequestType.info:
        pass

    if req == RequestType.add:
        pass

    if req == RequestType.update:
        dict = request.json['data']
        if not remarks.update(dict):
            return jsonify(judge=False, id=INVALID_ID)

        return jsonify(judge=True)

    if req == RequestType.target:
        project_id = session['project_id']
        list = remarks.get_list(project_id=project_id, is_dict=True)
        if not list:
            return jsonify(judge=False, id=INVALID_ID)
        return jsonify(judge=True, remark=list[0])

    if req == RequestType.delete:
        pass


@editor.route(Const.ROOT_URL + '/size', methods=['POST'])
@login_required
def size():
    dict = request.json if ('application/json' in request.headers['Content-Type']) else {
        'req': int(request.form['req']),
    }

    req = dict['req']
    sizes = Sizes()

    if req == RequestType.info:
        pass

    if req == RequestType.add:
        pass

    if req == RequestType.update:
        dict = request.json['data']
        if not sizes.update(dict):
            return jsonify(judge=False, id=INVALID_ID)

        return jsonify(judge=True)

    if req == RequestType.target:
        pass

    if req == RequestType.delete:
        pass


@editor.route(Const.ROOT_URL + '/cut-image', methods=['POST'])
@login_required
def cut_image():
    dict = request.json if ('application/json' in request.headers['Content-Type']) else {
        'req': int(request.form['req']),
    }

    req = dict['req']

    if req == RequestType.info:
        pass

    if req == RequestType.add:
        pass

    if req == RequestType.update:
        if not get_app_config().AWS_USED:
            project_id = session['project_id']
            CutOut.execute(project_id)

        return jsonify(judge=True)

    if req == RequestType.target:
        pass

    if req == RequestType.delete:
        pass


@editor.route(Const.ROOT_URL + '/inspection', methods=['POST'])
@login_required
def inspection():
    dict = request.json if ('application/json' in request.headers['Content-Type']) else {
        'req': int(request.form['req']),
    }
    req = dict['req']
    inspections = Inspections()

    project_id = session['project_id']
    if req == RequestType.info:
        list = inspections.get_list(project_id=project_id, is_dict=True)
        if not list:
            dict = {
                'project_id': project_id,
                'divide': DivideType.nine,
            }
            list.append(inspections.insert([dict], is_dict=True)[0])

        return jsonify(judge=True, dict=list[0])

    if req == RequestType.add:
        pass

    if req == RequestType.update:
        dict = request.json['data']
        if not inspections.update(dict):
            return jsonify(judge=False, id=INVALID_ID)
        return jsonify(judge=True, dict=dict)

    if req == RequestType.target:
        pass

    if req == RequestType.delete:
        pass


@editor.route(Const.ROOT_URL + '/section', methods=['POST'])
@login_required
def section():
    dict = request.json if ('application/json' in request.headers['Content-Type']) else {
        'req': int(request.form['req']),
    }
    req = dict['req']
    sections = Sections()

    if req == RequestType.info:
        page_id = dict['page_id']
        list = sections.get_entry_ByPageID(page_id, is_dict=True)
        return jsonify(judge=True, dict=list)

    if req == RequestType.add:
        pass

    if req == RequestType.update:
        length = 0
        inspection = request.json['inspection']
        if inspection['divide'] == DivideType.six:
            length = 6
        elif inspection['divide'] == DivideType.nine:
            length = 9
        elif inspection['divide'] == DivideType.twelve:
            length = 12
        elif inspection['divide'] == DivideType.twentyFive:
            length = 25
        elif inspection['divide'] == DivideType.thirtySix:
            length = 36

        page_list = request.json['page_list']
        section_list = [e['section'] for e in page_list]
        for section in section_list:
            section['data'] = [{'index': i, 'check': False} for i in range(length)]
        sections.bulk_update(section_list)

        return jsonify(judge=True, list=section_list)

    if req == RequestType.target:
        section = request.json['section']
        #print(section)
        if not sections.update(section):
            return jsonify(judge=False, id=INVALID_ID)
        return jsonify(judge=True, dict=section)

    if req == RequestType.delete:
        pass

# @editor.route(Const.ROOT_URL + '/cut-image', methods=['POST'])
# def cut_image():
#     dict = request.json if ('application/json' in request.headers['Content-Type']) else {
#         'req': int(request.form['req']),
#     }

#     remarks = Remarks()

#     req = dict['req']
#     symbol_scale = str(dict['symbol_scale'])
#     area_list = dict['areaList']

#     if req == RequestType.info:
#         pass

#     if req == RequestType.add:
#         pass

#     if req == RequestType.update:
#         project_id = session['project_id']
#         remark_list = remarks.get_list(project_id=project_id, is_dict=True)
#         if not symbol_scale == str(remark_list[0]['symbol_scale']):
#             CutOut.execute(project_id)
#         else:
#             projects = Projects()
#             pages = Pages()

#             root = projects.get_directory(project_id)
#             area_directory = os.path.join(root, CLASSIFICATION_DIRECTORY_NAME)

#             if not os.path.exists(area_directory):
#                 os.makedirs(area_directory)

#             space = math.floor(CUT_OUT_SIZE_DEFAULT * float(symbol_scale))

#             current_page_id = -1
#             for index, area in enumerate(area_list):
#                 page_id = area['page_id']
#                 page = pages.get_entry(area['page_id'], is_dict=True)

#                 if index == 0:
#                     current_page_id = page_id

#                 file_name = str(area['id']) + ".png"
#                 file_path = os.path.join(area_directory, file_name)

#                 rect = {
#                     'x': area['vertexs'][0]['x'] - space,
#                     'y': area['vertexs'][0]['y'] - space,
#                     'w': space * 2,
#                     'h': space * 2,
#                 }
#                 top = rect['y']
#                 bottom = rect['y'] + rect['h']
#                 left = rect['x']
#                 right = rect['x'] + rect['w']

#                 if index == 0 or current_page_id != page_id:
#                     page_image = _imread(page['path'])
#                     current_page_id = page_id

#                 trim_image = page_image[top:bottom, left:right]
#                 cv2.imwrite(file_path, trim_image)

#         return jsonify(judge=True)

#     if req == RequestType.target:
#         pass

#     if req == RequestType.delete:
#         pass


def _imread(filename, flags=cv2.IMREAD_COLOR, dtype=np.uint8):
    try:
        n = np.fromfile(filename, dtype)
        img = cv2.imdecode(n, flags)
        return img
    except Exception as e:
        print(e)
        return None


def recognize_legend(project_id):
    areas = Areas()
    legends = Legends()

    order_areas_list = areas.get_order_list(project_id=project_id, order=Order.area_legend, is_dict=True)
    print(order_areas_list)
    try:
        ids, ret2, icn = detect_table_nonAI_ver2.main(order_areas_list)
    except Exception as e:
        print(e)
        return False

    print(ids, len(ids)) #囲ったところだけ切り抜いた画像pathリスト
    print(ret2, len(ret2)) #ocrで読み取った文字列リスト
    print(icn, len(icn)) #iconの画像(両サイドの余白はカットされている)パス

    def to_dict(_i):
        area_path = ids[_i]
        name = ret2[_i]
        path = icn[_i]
        dict = {
            'id': INVALID_ID,
            'project_id': project_id,
            'symbol_id': INVALID_ID,
            'area_path': area_path,
            'name': name,
            'product_name': "",
            'path': path,
            'index': _i,
            'option': {},
        }
        return dict
    dict_list = [to_dict(i) for i in range(len(icn))]

    id_list = legends.insert(dict_list)
    if not id_list:
        return False
    return True

# @brief add start area および context アドレス モードのインターフェイスが追加されました PSDCD linanjie 2023/01/04
# ==================================================addressmodeモード==================================================
@editor.route(Const.ROOT_URL + '/area_address', methods=['POST'])
@login_required
def area_address():
    dict = request.json if ('application/json' in request.headers['Content-Type']) else {
        'req': int(request.form['req']),
    }

    req = dict['req']
    if 'project_id' in session:
        project_id = session['project_id']
    areas = Areas()
    context_address = ContextsAddress()
    projects = Projects()

    if 'project_id' in session:
        root = projects.get_directory(project_id)
        area_directory = os.path.join(root, CLASSIFICATION_DIRECTORY_NAME)

    if req == RequestType.info:
        if 'page_id' in dict:
            page_id = dict['page_id']
        else:
            page_id = ALL_ID
        state = dict['state']
        if state == StateType.normal_state:
            join_list = context_address.get_join_list(project_id=project_id, page_id=page_id, vertexs=None, is_dict=True)
            legend_list = context_address.get_legendtable_address_join_list(project_id=project_id, is_dict=True)
            project_entry = projects.get_entry(id=project_id, is_dict=True)
            return jsonify(judge=True, list=join_list, legend_list=legend_list, project=project_entry)
        elif state == StateType.single_state:
            area_id = dict['area_id']
            join_list = areas.get_join_area(area_id=area_id, project_id=project_id, page_id=page_id, is_dict=True)
            return jsonify(judge=True, list=join_list)
        elif state == StateType.del_state:
            dict = request.json['data']
            id_list = [item['id'] for item in dict]
            join_list = areas.get_join_list(id_list=id_list, project_id=project_id, page_id=page_id, is_dict=True)
            return jsonify(list=join_list)
        else:
            return jsonify(judge=False, id=INVALID_ID)

    # シンボルがドメイン内に含まれているかどうか、および対応する含まれている情報を確認する
    def determine_contains(area_list, symbol_list):
        path_area_list = AreaUtil.get_path_area_list(area_list)
        areas_contains_weight_dict = AreaUtil.get_areas_contains_weight_dict(path_area_list)

        symbol_list_for_number = []
        symbol_area_id_list_for_number_delete = []
        for symbol in symbol_list:
            is_contains, symbol_coordinate = AreaUtil.determine_parent_area(tuple(symbol['vertexs'][0].values()), path_area_list, areas_contains_weight_dict)
            if is_contains:
                symbol['parent_order_id'] = symbol_coordinate['parent_order_id']
                symbol_list_for_number.append(symbol)
            else:
                symbol_area_id_list_for_number_delete.append(symbol['id'])
        return symbol_list_for_number, symbol_area_id_list_for_number_delete

    # 自動マッチング後、シンボルを手動で追加したり、シンボルマッチングを置き換えたりする場合は、対応するシンボル番号情報と親ケースに対応する最大アドレス情報を更新します
    def auto_num_context_address(page_id, project_id, parent_legend_id, parent_legend_context_address_dict, context_address_dict, new_symbol_auto_num_name):
        parent_legend_max_symbol_num = parent_legend_context_address_dict['max_symbol_num']
        parent_legend_max_symbol_num = 0 if parent_legend_max_symbol_num is None else parent_legend_max_symbol_num
        pages = Pages()
        # 自動的に一致した場合
        if pages.get_entry(id=page_id).is_auto_num:
            # システム名で既存のすべての番号を検索し、次の空白の番号付きアドレスを取得します
            filters = []
            filters.append(ContextAddressTable.auto_num_name == str(new_symbol_auto_num_name))
            filters.append(ContextAddressTable.area_id.in_(list(map(lambda area: area.id, areas.get_list(project_id=project_id, page_id=page_id)))))
            context_address_list_group_by = context_address.get_list_group_by(filters=filters, group_by=ContextAddressTable.auto_num_name)
            if not context_address_list_group_by:
                context_address_dict['max_symbol_num'] = 1
                parent_legend_context_address_dict['max_symbol_num'] = 2
                context_address.update_for_single(parent_legend_context_address_dict)
                return context_address_dict

            max_symbol_num_list = context_address_list_group_by[0][1]
            def get_next_max_symbol_num(max_symbol_num_list, parent_legend_max_symbol_num):
                max_symbol_num_list = list(filter(None, max_symbol_num_list))
                if not max_symbol_num_list:
                    return 1
                max_symbol_num_list.sort()
                begin = max_symbol_num_list[0]
                end = max_symbol_num_list[-1]
                new_range_list = list(range(begin, end + 3))
                dif = list(set(new_range_list).difference(set(max_symbol_num_list)))
                dif.sort()
                for index, elem in enumerate(dif):
                    if parent_legend_max_symbol_num < elem:
                        parent_legend_max_symbol_num = elem
                        break
                    if parent_legend_max_symbol_num == elem:
                        parent_legend_max_symbol_num = dif[index + 1]
                        break
                    if parent_legend_max_symbol_num > elem:
                        return parent_legend_max_symbol_num + 1
                return parent_legend_max_symbol_num

            next_max_symbol_num = get_next_max_symbol_num(max_symbol_num_list,parent_legend_max_symbol_num)
            next_parent_legend_symbol_num = 255 if next_max_symbol_num > 255 else next_max_symbol_num
            if next_parent_legend_symbol_num == 255:
                context_address_area_id_list = list(map(lambda area: area.id, areas.get_list(filters=[AreaTable.parent_legend_id == parent_legend_id])))
                filters = []
                filters.append(ContextAddressTable.area_id.in_(context_address_area_id_list))
                filters.append(ContextAddressTable.max_symbol_num == 255)
                if context_address.get_entry_optional(filters=filters):
                    new_max_symbol_num = None
                else:
                    new_max_symbol_num = parent_legend_max_symbol_num
                    parent_legend_context_address_dict['max_symbol_num'] = next_parent_legend_symbol_num
                    context_address.update_for_single(parent_legend_context_address_dict)

            elif next_parent_legend_symbol_num > parent_legend_max_symbol_num:
                new_max_symbol_num = parent_legend_max_symbol_num
                parent_legend_context_address_dict['max_symbol_num'] = next_parent_legend_symbol_num
                context_address.update_for_single(parent_legend_context_address_dict)
            elif next_parent_legend_symbol_num  ==  parent_legend_max_symbol_num:
                new_max_symbol_num = next_parent_legend_symbol_num
            context_address_dict['max_symbol_num'] = new_max_symbol_num
        return context_address_dict

    if req == RequestType.add:
        dict = request.json['data']
        dict['project_id'] = project_id
        page_id = dict['page_id']
        order = dict['order']
        dict['is_manual'] = True  # 手動追加
        dict['is_customized'] = False  # フィールドの正方形またはポリゴンはカスタマイズされていません
        if order == Order.area_rect or order == Order.area_polygon:
            dict['z_index'] = areas.get_last_z_index(project_id=project_id, page_id=page_id, order=order) + 1

        id_list = areas.insert([dict])
        if not id_list:
            return jsonify(judge=False, id=INVALID_ID)
        if order == Order.area_legend:
            return jsonify(judge=True, id=id_list[0])
        if order == Order.area_square:
            parent_legend_context_address_dict = context_address.get_entry(area_id=dict['parent_legend_id'], is_dict=True)
            new_symbol_auto_num_name = AreaUtil.get_auto_num_name(parent_legend_context_address_dict)
            context_dict = {
                'area_id': id_list[0],
                'name_type': parent_legend_context_address_dict['name_type'],
                'name': parent_legend_context_address_dict['name'],
                'self_fire_begin': parent_legend_context_address_dict['self_fire_begin'],
                'self_fire_end': parent_legend_context_address_dict['self_fire_end'],
                'rank_begin': parent_legend_context_address_dict['rank_begin'],
                'rank_end': parent_legend_context_address_dict['rank_end'],
                'building_num': parent_legend_context_address_dict['building_num'],
                'floor': parent_legend_context_address_dict['floor'],
                'region': parent_legend_context_address_dict['region'],
                'font_size': parent_legend_context_address_dict['font_size'],
                'auto_num_name': new_symbol_auto_num_name,
            }

            context_dict = auto_num_context_address(dict['page_id'], project_id, dict['parent_legend_id'], parent_legend_context_address_dict, context_dict, new_symbol_auto_num_name)
            context_address_id_list = context_address.insert([context_dict])
            if not context_address_id_list:
                return jsonify(judge=False, id=INVALID_ID)
            dict['context_id'] = context_address_id_list[0]
            return jsonify(judge=True, id=id_list[0], area=dict)
        if order == Order.area_rect or order == Order.area_polygon:
            context_dict = {
                'area_id': id_list[0],
                'name_type': dict['name_type'],
                'name': dict['name'],
                'self_fire_begin': dict['self_fire_begin'],
                'self_fire_end': dict['self_fire_end'],
                'rank_begin': dict['rank_begin'],
                'rank_end': dict['rank_end'],
            }
            context_address_id_list = context_address.insert([context_dict])
            if not context_address_id_list:
                return jsonify(judge=False, id=INVALID_ID)
            return jsonify(judge=True, id=id_list[0])
        return jsonify(judge=False, id=INVALID_ID)

    if req == RequestType.update:
        dict = request.json['data']
        dict['project_id'] = project_id
        dict['is_manual'] = True  # 手動修正
        if not areas.update(dict):
            return jsonify(judge=False, id=INVALID_ID)

        # 拾い出し画像更新
        if not get_app_config().AWS_USED:
            file_name = str(dict['id']) + ".png"
            file_path = os.path.join(area_directory, file_name)
            if os.path.exists(file_path):
                pages = Pages()
                remarks = Remarks()
                remark_list = remarks.get_list(project_id=project_id, is_dict=True)
                symbol_scale = remark_list[0]['symbol_scale']
                space = math.floor(CUT_OUT_SIZE_DEFAULT * float(symbol_scale))
                rect = {
                    'x': dict['vertexs'][0]['x'] - space,
                    'y': dict['vertexs'][0]['y'] - space,
                    'w': space * 2,
                    'h': space * 2,
                }
                top = rect['y']
                bottom = rect['y'] + rect['h']
                left = rect['x']
                right = rect['x'] + rect['w']
                page = pages.get_entry(dict['page_id'], is_dict=True)
                page_image = _imread(page['path'])
                trim_image = page_image[top:bottom, left:right]
                cv2.imwrite(file_path, trim_image)
        return jsonify(judge=True, dict=dict)

    # 単一の symbol 置換
    if req == RequestType.target:
        data = request.json['data']
        if not areas.delete([data['id']]):
            return jsonify(judge=False)

        new_symbol_area = {}
        new_symbol_area['project_id'] = project_id
        page_id = data['page_id']
        new_symbol_area['page_id'] = page_id
        new_symbol_area['parent_id'] = data['new_parent_id']
        new_parent_legend_id = data['new_parent_legend_id']
        new_symbol_area['parent_legend_id'] = new_parent_legend_id
        new_symbol_area['order'] = Order.area_square
        new_symbol_area['shape'] = Shape.square
        new_symbol_area['vertexs'] = data['vertexs']
        new_symbol_area['is_auto'] = False
        new_symbol_area['is_manual'] = True
        new_symbol_area['is_customized'] = False
        new_symbol_area_id = areas.insert([new_symbol_area])[0]
        if not new_symbol_area_id:
            return jsonify(judge=False)

        new_parent_contexts_address = context_address.get_entry(area_id=new_parent_legend_id, is_dict=True)
        new_symbol_contexts_address = ContextAddressTable(new_parent_contexts_address)
        new_symbol_contexts_address.font_size = data['font_size']
        new_symbol_auto_num_name = AreaUtil.get_auto_num_name(new_parent_contexts_address)
        new_symbol_contexts_address.auto_num_name = new_symbol_auto_num_name
        new_symbol_contexts_address.area_id = new_symbol_area_id

        new_symbol_contexts_address_dict = ContextAddressTable.to_dict(new_symbol_contexts_address)
        new_symbol_contexts_address_dict = auto_num_context_address(page_id, project_id, data['new_parent_legend_id'], new_parent_contexts_address, new_symbol_contexts_address_dict, new_symbol_auto_num_name)
        if not context_address.insert([new_symbol_contexts_address_dict]):
            return jsonify(judge=False)
        return jsonify(judge=True, area={**new_symbol_area, **new_symbol_contexts_address_dict})

    if req == RequestType.delete:
        dict = request.json['data']
        id_list = [item['id'] for item in dict]
        areas.delete(id_list)

        # 拾い出し画像削除
        if not get_app_config().AWS_USED:
            for i in range(len(id_list)):
                order = dict[i]['order']
                if order == Order.area_square:
                    file_name = str(id_list[i]) + ".png"
                    file_path = os.path.join(area_directory, file_name)
                    if os.path.exists(file_path):
                        os.remove(file_path)

        return jsonify(judge=True)

    # 自動マッチング
    if req == RequestType.number:
        # ページに自動的に割り当てられたタグを設定する
        pages = Pages()
        page_dict = dict['data']
        page_dict['is_auto_num'] = True
        pages.update(page_dict)

        filters = []
        filters.append(AreaTable.is_customized.is_(False))
        filters.append(AreaTable.vertexs.isnot(None))
        # グラフ内のフィールドと対応するシンボル(自動シンボルとユーザークリックによって追加されたカスタムシンボルを含む)をクエリします
        area_symbol_list = areas.get_list(filters=filters, project_id=project_id, page_id=page_dict['page_id'], is_dict=True)

        area_list = list(filter(lambda ele: ele['parent_legend_id'] is None, area_symbol_list))
        symbol_list = list(filter(lambda ele: ele['parent_legend_id'] is not None, area_symbol_list))
        symbol_list_for_number, symbol_area_id_list_for_number_delete = determine_contains(area_list, symbol_list)

        # 自動マッチングは、フィールド外のシンボルの番号を削除します
        context_address.bulk_update_general(context_address.get_list(filters=[ContextAddressTable.area_id.in_(symbol_area_id_list_for_number_delete)]), data={'max_symbol_num': None})

        # 上から下、左から右に並べ替える
        def symbol_order_reset(symbol_vertexs_list):
            symbol_vertexs_array = np.array(symbol_vertexs_list)
            arrSortedIndex = np.lexsort((symbol_vertexs_array[:, 0], symbol_vertexs_array[:, 1]))
            return symbol_vertexs_array[arrSortedIndex, :].tolist()

        # 同じparent_order_idでグループ化
        symbol_list_for_number.sort(key=itemgetter('parent_order_id'))
        for parent_order_id, items in groupby(symbol_list_for_number, key=itemgetter('parent_order_id')):
            symbol_vertexs_list = []
            item_list = []

            # クエリは、対応するparent_order_idのシステム名を処理し、値を割り当てます
            parent_order_context_address = context_address.get_entry(area_id=parent_order_id, is_dict=True)
            parent_auto_num_name = AreaUtil.get_auto_num_name(parent_order_context_address)
            for item in items:
                item_list.append(item)
                symbol_vertexs_list.append(list(item['vertexs'][0].values()))
                symbol_vertexs_list = symbol_order_reset(symbol_vertexs_list)

            filters = []
            filters.append(AreaTable.parent_id == parent_order_id)
            filters.append(AreaTable.parent_legend_id.is_(None))
            filters.append(AreaTable.vertexs.is_(None))
            filters.append(AreaTable.is_customized.is_(False))
            legend_context_address = context_address.get_entry(area_id=areas.get_entry_optional(filters=filters).id, is_dict=True)
            context_address_max_symbol_num = legend_context_address['max_symbol_num']
            context_address_max_symbol_num = 1 if context_address_max_symbol_num is None else context_address_max_symbol_num
            for index, symbol_vertexs_order in enumerate(symbol_vertexs_list):
                for item in item_list:
                    item_vertex = item['vertexs'][0]
                    if item_vertex['x'] == symbol_vertexs_order[0] and item_vertex['y'] == symbol_vertexs_order[1]:
                        # 数は 255 を超えることはできません
                        symbol_max_num = index + context_address_max_symbol_num
                        item['contexts_address']['max_symbol_num'] = None if symbol_max_num > 255 else symbol_max_num
                        item['contexts_address']['auto_num_name'] = parent_auto_num_name

            # 対応する例で使用可能な最大アドレス値をバックフィルします
            context_address_max_symbol_num = 255 if symbol_max_num + 1 > 255 else symbol_max_num + 1
            legend_context_address['max_symbol_num'] = context_address_max_symbol_num
            context_address.update_for_single(legend_context_address)

        symbol_list_for_number_contexts_address = [symbol_for_number['contexts_address'] for symbol_for_number in symbol_list_for_number]
        symbol_list_for_number_contexts_address.sort(key=itemgetter('id'))
        context_address.bulk_update_list(symbol_list_for_number_contexts_address)

        for symbol_for_update in symbol_list_for_number:
            areas.update(symbol_for_update)
        return jsonify(judge=True)


# @brief mod 左側の凡例のリストが関連しています PSDCD linanjie 2023/02/07
@editor.route(Const.ROOT_URL + '/legendtable_address', methods=['POST'])
@login_required
def legendtable_address():
    dict = request.json if ('application/json' in request.headers['Content-Type']) else {
        'req': int(request.form['req']),
    }

    req = dict['req']
    project_id = ALL_ID
    if 'project_id' in session:
        project_id = session['project_id']
    if 'page_id' in dict:
        page_id = dict['page_id']
    areas = Areas()
    context_address = ContextsAddress()
    if req == RequestType.info:
        state = dict['state']
        if state == StateType.normal_state:
            join_list = context_address.get_legendtable_address_join_list(project_id=project_id, is_dict=True)
            return jsonify(judge=True, list=join_list)

    if req == RequestType.add:
        dict = request.json['data']
        dict['project_id'] = project_id
        dict['page_id'] = page_id
        dict['is_manual'] = True  # 手動追加
        dict['is_customized'] = True  # 凡例の追加はカスタマイズされます
        area_id_list = areas.insert([dict])
        context_address_data = dict
        context_address_data['area_id'] = area_id_list[0]
        context_address_area_id_list = context_address.insert([context_address_data])
        if not area_id_list or not context_address_area_id_list:
            return jsonify(judge=False)
        return jsonify(judge=True)

    if req == RequestType.update:
        pass

    if req == RequestType.target:
        pass

    # 左側の凡例リストと、symbol 対応のarea_addressとcontext_addressをピックアップするレコードを削除します
    if req == RequestType.delete:
        area_id = dict['data']['area_id']
        areas = Areas()
        area_id_list = list(map(lambda area: area.id, areas.get_join_list(id_list=[area_id])))
        symbol_area_id_list = list(map(lambda area: area.id, areas.get_join_list(parent_legend_id=area_id)))
        area_id_list.extend(symbol_area_id_list)
        if not areas.delete(area_id_list):
            return jsonify(judge=False)
        return jsonify(judge=True)


@editor.route(Const.ROOT_URL + '/context_address', methods=['POST'])
@login_required
def context_address():
    dict = request.json if ('application/json' in request.headers['Content-Type']) else {
        'req': int(request.form['req']),
    }

    req = dict['req']
    context_address = ContextsAddress()

    if 'project_id' in session:
        project_id = session['project_id']

    if req == RequestType.info:
        entry = context_address.get_entry(id=dict['data']['context_id'], is_dict=True)
        if not entry:
            return jsonify(judge=False)
        return jsonify(judge=True, list=[entry])

    if req == RequestType.add:
        pass

    if req == RequestType.update:
        state = dict['state']
        data = dict['data']
        if state == UpdateType.relation_update_state and not context_address.update_for_relation(data):
            return jsonify(judge=False, id=INVALID_ID)
        if state == UpdateType.single_update_state and not context_address.update_for_single(data):
            return jsonify(judge=False, id=INVALID_ID)
        if state == UpdateType.bulk_update_state:
            areas = Areas()
            context_address_area_id_list = list(map(lambda area: area.id, areas.get_list(filters=[AreaTable.parent_legend_id.isnot(None)], project_id=project_id, page_id=data['page_id'])))
            context_address_area_id_list.extend(data['legend_id_list'])
            if not context_address.bulk_update_general(context_address.get_list(filters=[ContextAddressTable.area_id.in_(context_address_area_id_list)]), data={'font_size': data['font_size']}):
                return jsonify(judge=False, id=INVALID_ID)
            return jsonify(judge=True)
        return jsonify(judge=True)

    if req == RequestType.update_all:
        data = dict['data']
        data['project_id'] = project_id
        if not context_address.bulk_update(data):
            return jsonify(judge=False, id=INVALID_ID)
        return jsonify(judge=True)

    if req == RequestType.target:
        pass

    if req == RequestType.delete:
        pass
# @brief add end area および context アドレス モードのインターフェイスが追加されました PSDCD linanjie 2023/01/04